﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.Serialization;
using System.Reflection;

namespace EditoneLib.Serialization
{
    [DataContract(Namespace = "http://editone.app/v1")]
    public class Clip : IEditoneSerializable
    {        
        public IEditoneSerializer Serializer { protected get; set; }

        [DataMember]
        public TimeSpan Offset { get; set; }

        [DataMember]
        public string TypeName { get; set; }

        [DataMember]
        public string Source { get; set; }

        [DataMember]
        public Dictionary<string, dynamic> Properties { get; set; }

        public IClip DelegatedClip
        {
            get
            {
                var clip = CreateClip(TypeName);

                if (clip is IHasStream)
                {
                    ((IHasStream)clip).Stream = Serializer.LoadStreamAsync(Source).Result;
                }

                // Set properties
                foreach (var prop in GetClipProperties(TypeName))
                {
                    if (Properties.ContainsKey(prop.Name))
                    {
                        prop.SetValue(clip, Properties[prop.Name]);
                    }
                }

                return clip;
            }
            set
            {
                TypeName = value.GetType().FullName;
                
                if (value is IHasStream)
                {
                    Source = Serializer.SaveStreamAsync(((IHasStream)value).Stream).Result;
                }

                // Assign properties outside of IClip
                Properties = new Dictionary<string, dynamic>();
                foreach (var prop in GetClipProperties(TypeName))
                {
                    Properties[prop.Name] = prop.GetValue(value);
                }
            }
        }

        public static IClip CreateClip(string typeName)
        {
            var type = Type.GetType(typeName);
            IClip clip = Activator.CreateInstance(type) as IClip;

            return clip;
        }

        private IEnumerable<PropertyInfo> GetClipProperties(string typeName)
        {
            return Type.GetType(typeName).GetRuntimeProperties()
                .Where((prop) =>
                    prop.CanRead && prop.CanWrite
                    && prop.GetIndexParameters().Length == 0
                    && typeof(IClip).GetRuntimeProperty(prop.Name) == null
                    && typeof(IHasStream).GetRuntimeProperty(prop.Name) == null
                );
        }
    }
}
